import { ethers } from 'ethers';
import { Chain } from '@prisma/client';

export class EVMTrader {
  private provider: ethers.JsonRpcProvider;
  private wallet: ethers.Signer;
  private chain: Chain;

  constructor(chain: Chain) {
    this.chain = chain;
    this.provider = new ethers.JsonRpcProvider(this.getRpcUrl(chain));
    
    if (!process.env.PRIVATE_KEY) {
      throw new Error('PRIVATE_KEY环境变量未设置');
    }
    
    try {
      // 检查是否为开发模式
      if (process.env.PRIVATE_KEY === 'development_mode' || 
          process.env.PRIVATE_KEY === 'your_private_key_here' || 
          process.env.PRIVATE_KEY === '0xyour_private_key_here') {
        console.log(`开发模式：生成临时${chain}钱包`);
        this.wallet = ethers.Wallet.createRandom().connect(this.provider);
        this.wallet.getAddress().then(addr => console.log(`${chain}临时钱包地址:`, addr));
      } else {
        this.wallet = new ethers.Wallet(process.env.PRIVATE_KEY, this.provider);
        this.wallet.getAddress().then(addr => console.log(`${chain}钱包地址:`, addr));
      }
    } catch (error) {
      console.log(`${chain}私钥格式错误，生成临时钱包`);
      this.wallet = ethers.Wallet.createRandom().connect(this.provider);
      this.wallet.getAddress().then(addr => console.log(`${chain}临时钱包地址:`, addr));
    }
  }

  /**
   * 买入代币
   * @param tokenAddress 代币合约地址
   * @param ethAmount ETH/BNB数量
   */
  async buy(tokenAddress: string, ethAmount: number): Promise<string> {
    try {
      console.log(`开始买入 ${tokenAddress}, ${this.getNativeCurrency()}数量: ${ethAmount}`);
      
      // 获取路由器合约
      const routerAddress = this.getRouterAddress();
      const routerAbi = this.getRouterAbi();
      const router = new ethers.Contract(routerAddress, routerAbi, this.wallet);
      
      // 获取WETH地址
      const wethAddress = await router.WETH();
      
      // 设置交易路径
      const path = [wethAddress, tokenAddress];
      
      // 获取预期输出数量
      const amountIn = ethers.parseEther(ethAmount.toString());
      const amountsOut = await router.getAmountsOut(amountIn, path);
      const amountOutMin = amountsOut[1] * BigInt(95) / BigInt(100); // 5%滑点
      
      // 设置截止时间（当前时间 + 20分钟）
      const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
      
      // 获取钱包地址
      const walletAddress = await this.wallet.getAddress();
      
      // 执行交换
      const tx = await router.swapExactETHForTokens(
        amountOutMin,
        path,
        walletAddress,
        deadline,
        {
          value: amountIn,
          gasLimit: 300000
        }
      );
      
      // 等待交易确认
      const receipt = await tx.wait();
      
      console.log(`${this.chain}买入交易完成: ${receipt.hash}`);
      return receipt.hash;
      
    } catch (error) {
      console.error(`${this.chain}买入失败:`, error);
      throw error;
    }
  }

  /**
   * 卖出代币
   * @param tokenAddress 代币合约地址
   * @param tokenAmount 代币数量
   */
  async sell(tokenAddress: string, tokenAmount: number): Promise<string> {
    try {
      console.log(`开始卖出 ${tokenAddress}, 代币数量: ${tokenAmount}`);
      
      // 获取代币合约
      const tokenContract = new ethers.Contract(
        tokenAddress,
        ['function decimals() view returns (uint8)', 'function approve(address spender, uint256 amount) returns (bool)'],
        this.wallet
      );
      
      // 获取代币精度
      const decimals = await tokenContract.decimals();
      const amountIn = ethers.parseUnits(tokenAmount.toString(), decimals);
      
      // 获取路由器合约
      const routerAddress = this.getRouterAddress();
      const routerAbi = this.getRouterAbi();
      const router = new ethers.Contract(routerAddress, routerAbi, this.wallet);
      
      // 授权路由器使用代币
      const approveTx = await tokenContract.approve(routerAddress, amountIn);
      await approveTx.wait();
      
      // 获取WETH地址
      const wethAddress = await router.WETH();
      
      // 设置交易路径
      const path = [tokenAddress, wethAddress];
      
      // 获取预期输出数量
      const amountsOut = await router.getAmountsOut(amountIn, path);
      const amountOutMin = amountsOut[1] * BigInt(95) / BigInt(100); // 5%滑点
      
      // 设置截止时间
      const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
      
      // 获取钱包地址
      const walletAddress = await this.wallet.getAddress();
      
      // 执行交换
      const tx = await router.swapExactTokensForETH(
        amountIn,
        amountOutMin,
        path,
        walletAddress,
        deadline,
        {
          gasLimit: 300000
        }
      );
      
      // 等待交易确认
      const receipt = await tx.wait();
      
      console.log(`${this.chain}卖出交易完成: ${receipt.hash}`);
      return receipt.hash;
      
    } catch (error) {
      console.error(`${this.chain}卖出失败:`, error);
      throw error;
    }
  }

  /**
   * 获取原生货币余额
   */
  async getBalance(): Promise<number> {
    const walletAddress = await this.wallet.getAddress();
    const balance = await this.provider.getBalance(walletAddress);
    return parseFloat(ethers.formatEther(balance));
  }

  /**
   * 获取代币余额
   */
  async getTokenBalance(tokenAddress: string): Promise<number> {
    try {
      const tokenContract = new ethers.Contract(
        tokenAddress,
        [
          'function balanceOf(address owner) view returns (uint256)',
          'function decimals() view returns (uint8)'
        ],
        this.provider
      );
      
      const walletAddress = await this.wallet.getAddress();
      const [balance, decimals] = await Promise.all([
        tokenContract.balanceOf(walletAddress),
        tokenContract.decimals()
      ]);
      
      return parseFloat(ethers.formatUnits(balance, decimals));
    } catch (error) {
      console.error('获取代币余额失败:', error);
      return 0;
    }
  }

  /**
   * 获取钱包地址
   */
  async getWalletAddress(): Promise<string> {
    return await this.wallet.getAddress();
  }

  /**
   * 获取RPC URL
   */
  private getRpcUrl(chain: Chain): string {
    switch (chain) {
      case Chain.BSC:
        return process.env.BSC_RPC_URL || 'https://bsc-dataseed1.binance.org/';
      case Chain.BASE:
        return process.env.BASE_RPC_URL || 'https://mainnet.base.org';
      default:
        throw new Error(`不支持的链: ${chain}`);
    }
  }

  /**
   * 获取路由器地址
   */
  private getRouterAddress(): string {
    switch (this.chain) {
      case Chain.BSC:
        return '0x10ED43C718714eb63d5aA57B78B54704E256024E'; // PancakeSwap Router
      case Chain.BASE:
        return '0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24'; // BaseSwap Router
      default:
        throw new Error(`不支持的链: ${this.chain}`);
    }
  }

  /**
   * 获取原生货币名称
   */
  private getNativeCurrency(): string {
    switch (this.chain) {
      case Chain.BSC:
        return 'BNB';
      case Chain.BASE:
        return 'ETH';
      default:
        return 'ETH';
    }
  }

  /**
   * 获取路由器ABI
   */
  private getRouterAbi(): string[] {
    return [
      'function WETH() external pure returns (address)',
      'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)',
      'function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)',
      'function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'
    ];
  }
}
